﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using ZeroSum.Extend.Cors.Configurations;
using ZeroSum.Extend.Cors.Constants;

namespace ZeroSum.Extend.Cors;

public static class CorsExtensions
{
    public static IServiceCollection AddCorsSupported(this IServiceCollection services, IConfiguration configuration,
        Action<CorsOptions>? corsOptionsHandler = default,
        Action<CorsPolicyBuilder>? corsPolicyBuilderHandler = default)
    {
        // 获取选项
        var corsOptions = configuration.GetSection(CorsConst.CorsOptions).Get<ZeroCorsOptions>();
        if (corsOptions is not {Enabled: true})
            return services;

        // 添加跨域服务
        services.AddCors(options =>
        {
            // 添加策略跨域
            options.AddPolicy(corsOptions.PolicyName, builder =>
            {
                // 判断是否设置了来源，因为 AllowAnyOrigin 不能和 AllowCredentials一起公用
                // 指定 AllowAnyOrigin 和 AllowCredentials 是不安全的配置，可能会导致跨网站请求伪造。 同时使用这两种方法来配置应用时，CORS 服务会返回无效的 CORS 响应。
                var isNotSetOrigins = corsOptions.WithOrigins == null || corsOptions.WithOrigins.Length == 0;

                // 如果没有配置来源，则允许所有来源
                // SetIsOriginAllowedToAllowWildcardSubdomains：将 IsOriginAllowed 策略的属性设置为一个函数，当计算是否允许源时，此函数允许源匹配已配置的通配符域。
                if (isNotSetOrigins) builder.AllowAnyOrigin();
                else
                    builder.WithOrigins(corsOptions.WithOrigins)
                        .SetIsOriginAllowedToAllowWildcardSubdomains();

                // 如果没有配置请求标头，则允许所有表头
                if (corsOptions.WithHeaders == null || corsOptions.WithHeaders.Length == 0) builder.AllowAnyHeader();
                else builder.WithHeaders(corsOptions.WithHeaders);

                // 如果没有配置任何请求谓词，则允许所有请求谓词
                if (corsOptions.WithMethods == null || corsOptions.WithMethods.Length == 0) builder.AllowAnyMethod();
                else builder.WithMethods(corsOptions.WithMethods);

                // 配置跨域凭据
                if (corsOptions.AllowCredentials && !isNotSetOrigins) builder.AllowCredentials();

                // 配置响应头
                if (corsOptions.WithExposedHeaders is {Length: > 0})
                    builder.WithExposedHeaders(corsOptions.WithExposedHeaders);

                // 设置预检过期时间
                if (corsOptions.SetPreflightMaxAge.HasValue)
                    builder.SetPreflightMaxAge(TimeSpan.FromSeconds(corsOptions.SetPreflightMaxAge.Value));

                // 添加自定义配置
                corsPolicyBuilderHandler?.Invoke(builder);
            });

            // 添加自定义配置
            corsOptionsHandler?.Invoke(options);
        });

        // 添加响应压缩
        //services.AddResponseCaching();

        return services;
    }

    public static IApplicationBuilder UseCorsSupported(this IApplicationBuilder builder)
    {
        var provider = builder.ApplicationServices;
        var configuration = provider.GetService<IConfiguration>();

        var corsOptions = configuration?.GetSection(CorsConst.CorsOptions).Get<ZeroCorsOptions>();
        if (corsOptions is not {Enabled: true})
            return builder;

        builder.UseCors(corsOptions.PolicyName);
        return builder;
    }
}